//////////////////////////////////////////////////////////////////////////////////
// Company:        RIT
// Engineer:       Cody Cziesler, Nick Desaulniers
//
// Create Date:    11:20:40 04/07/2011
// Design Name:    control_unit
// Module Name:    control_unit
// Project Name:   omicron
// Target Devices: Xilinx Spartan-3E
// Tool versions:
// Description:    The control unit of the cpu pipeline
//
// Revision:
// Revision 0.01 - File Created
// Revision 1.00 - Added cu_branch (CRC)
// Revision 2.00 - Stubbed out control_unit, needs substance (CRC)
// Revision 3.00 - Extended Branch bits (01 branch, 10 jump, 00 no branch, 11 should not occur)
//               - Fixed id_opcode switch
//		           - Modified cu_alu_opcode length
//		           - Filled in output signals
//		           - Added SUB alu opcode for branch instructions
// Revision 4.00 - Removed cu_reg_dest (CRC)
// Revision 5.00 - Changed LD and STR instructions to use the CPY opcode (CRC)
// Revision 6.00 - Spacing (CRC)
// Revision 7.00 - Removed params, added defines in include.v, changed cu_alu_opcode size (CRC)
//
//
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

`include "include.v"

module control_unit(
    input wire        clk,
    input wire        rst_n,
    input wire [3:0]  id_opcode,
    input wire [2:0]  id_function,
    output reg        cu_reg_load,          // RegLd
    output reg        cu_alu_sel_b,         // AluSelB
    output reg [4:0]  cu_alu_opcode,        // AluCtrl
    output reg        cu_dm_wea,            // MemWr
    output reg        cu_reg_data_loc,      // AluOrMem
    output reg [1:0]  cu_branch             // Branch
);

always@(posedge clk or negedge rst_n) begin
  if(!rst_n) begin
    cu_alu_opcode   <= `NOOP;
    cu_reg_load     <= 1'b0;
    cu_reg_data_loc <= 1'b0;
    cu_branch       <= 2'b00;
    cu_dm_wea       <= 1'b0;
    cu_alu_sel_b    <= 1'b0;
  end else begin
    case(id_opcode)
      4'b0000 : begin
        case (id_function)
          `NOOP_f : begin
            cu_alu_opcode   <= `NOOP;
            cu_reg_load     <= 1'b0;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `CPY_f : begin
            cu_alu_opcode   <= `CPY;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `ADD_f : begin
            cu_alu_opcode   <= `ADD;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `SUB_f : begin
            cu_alu_opcode   <= `SUB;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `MUL_f : begin
            cu_alu_opcode   <= `MUL;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `AND_f : begin
            cu_alu_opcode   <= `AND;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `OR_f : begin
            cu_alu_opcode   <= `OR;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `NOT_f : begin
            cu_alu_opcode   <= `NOT;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
        endcase
      end
      4'b0001 : begin
        case (id_function)
          `XOR_f : begin
            cu_alu_opcode   <= `XOR;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `NOR_f : begin
            cu_alu_opcode   <= `NOR;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `XNOR_f : begin
            cu_alu_opcode   <= `XNOR;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `LS_f : begin
            cu_alu_opcode   <= `LS;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `RS_f : begin
            cu_alu_opcode   <= `RS;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `INC_f : begin
            cu_alu_opcode   <= `INC;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
          `DEC_f : begin
            cu_alu_opcode   <= `DEC;
            cu_reg_load     <= 1'b1;
            cu_reg_data_loc <= 1'b0;
            cu_branch       <= 2'b00;
            cu_dm_wea       <= 1'b0;
            cu_alu_sel_b    <= 1'b0;
          end
        endcase
      end
      `BEQ_i : begin
        cu_alu_opcode   <= `SUB;
        cu_reg_load     <= 1'b0;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b01;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b0;
      end
      `BNE_i : begin
        cu_alu_opcode   <= `SUB;
        cu_reg_load     <= 1'b0;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b10;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b0;
      end
      `LD_i : begin
        cu_alu_opcode   <= `CPY;
        cu_reg_load     <= 1'b1;
        cu_reg_data_loc <= 1'b1;
        cu_branch       <= 2'b00;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b1;
      end
      `STR_i : begin
        cu_alu_opcode   <= `CPY;
        cu_reg_load     <= 1'b0;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b00;
        cu_dm_wea       <= 1'b1;
        cu_alu_sel_b    <= 1'b1;
      end
      `ADDI_i : begin
        cu_alu_opcode   <= `ADD;
        cu_reg_load     <= 1'b1;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b00;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b1;
      end
      `SUBI_i : begin
        cu_alu_opcode   <= `SUB;
        cu_reg_load     <= 1'b1;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b00;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b1;
      end
      `JMP_i : begin
        cu_alu_opcode   <= `NOOP;
        cu_reg_load     <= 1'b0;
        cu_reg_data_loc <= 1'b0;
        cu_branch       <= 2'b11;
        cu_dm_wea       <= 1'b0;
        cu_alu_sel_b    <= 1'b0;
      end
    endcase
  end
end

endmodule
